/**
 * 登录接口
 */

//引入Q模块
var Q = require('q');
//声明存放redis操作实例的变量
var redis = null;
//声明存放mongodb操作实例的变量
var db = null;
//引入公共函数
var util = require('../../util');
//引入crypto来辅助解密用户数据
var crypto = require('crypto');

//login入口函数
var index = function(getData, postData, config, _redis, _db) {
	var deferred = Q.defer();
	//将redis引入到公用redis
	redis = _redis;
	//将db引入到公用db
	db = _db;
	//APPID
	let appId = '';
	let appSecret = '';
	//判断是否存在wxCode,wxEncryptedData,wxIv
	util.isSet(postData.wxCode, postData.wxEncryptedData, postData.wxIv, postData.identity).then(function() {
		if(postData.identity == 'service') {
			appId = config.serviceAppId;
			appSecret = config.serviceAppSecret;
		}
		else {
			appId = config.clientAppId;
			appSecret = config.clientAppSecret;
		}
		//存在wxIv，获取sessionKey
		return getSessionKey(appId, appSecret, config.grantType, postData.wxCode);
	}, function() {
		//登录参数不正确，需要wxCode+wxEncryptedData+wxIv
		deferred.reject('-0006');
	}).then(function(data) {
		//获取sessionKey成功，开始解密用户数据
		return decryptUserData(appId, data.session_key, data.openid, data.expires_in, postData.wxEncryptedData, postData.wxIv);
	}, function() {
		//获取sessionKey失败
		deferred.reject('-0007');
	}).then(function(userdata) {
		//用户数据解密成功，开始生成3rdSession并存入redis缓存
		return create3rdSession(userdata);
	}, function() {
		//用户数据解密失败
		deferred.reject('-0008');
	}).then(function(result) {
		//生成3rdSession成功，开始存储用户数据
		return saveUserData(result, postData.storeId, postData.tableNum);
	}, function() {
		//生成3rdSession失败
		deferred.reject('-0009');
	}).then(function(result) {
		result.identity = postData.identity;
		return getUnreadMsg(result);
	}, function(errCode) {
		//存储用户数据失败
		deferred.reject(errCode);
	}).then(function(result) {
		return getStoreData(result);
	}, function() {
		//获取未读消息推送失败
		deferred.reject('-0062');
	}).then(function(result) {
		let noReceiveFunLogs = [];
		db.select('noReceiveFunLogs').then(function(_noReceiveFunLogs) {
			noReceiveFunLogs = _noReceiveFunLogs;
			return db.removeAll('noReceiveFunLogs', {});
		}, function() {
			//获取未读服务通知列表失败
			deferred.reject('-0100');
		}).then(function() {
			return db.select('storeOrder', {
				$or: [
					{payMode: 'wxPay', orderDone: false, userPayed: true}, 
					{payMode: 'cashPay', orderDone: false, userPayed: false}
				]
			});
		}, function() {
			deferred.reject('-0101');
		}).then(function(noDoneOrders) {
			//登录成功并返回3rdSession值
			deferred.resolve({
				storeData: result.storeData,
				_3rdSession: result._3rdSession,
				unreadMsgs: result.unreadMsgs || [],
				noReceiveFunLogs: noReceiveFunLogs || [],
				noDoneOrders: noDoneOrders || []
			});
		}, function() {
			deferred.reject('-0102');
		});
	}, function() {
		//查询商户信息失败
		deferred.reject('-0040');
	});
	return deferred.promise;
}

//获取sessionKey函数
var getSessionKey = function(appId, appSecret, grantType, wxCode) {
	var deferred = Q.defer();
	//发送GET请求到微信服务器请求sessionKey和用户数据
	util.get('https://api.weixin.qq.com/sns/jscode2session', {
		//小程序appid
		appid: appId,
		//小程序appSecret密钥
		secret: appSecret,
		//登录code
		js_code: wxCode,
		//登录类型
		grant_type: grantType
	}).then(function(data) {
		//判断是否存在session_key这个值
		console.log(data);
		if(data.session_key && data.openid && data.expires_in) {
			//返回数据
			deferred.resolve(data);
		}
		else {
			//参数不够返回失败
			deferred.reject();
		}
	}, function() {
		//请求失败
		deferred.reject();
	});
	return deferred.promise;
}

//解密用户数据函数
var decryptUserData = function(appid, sessionKey, openId, expire, wxEncryptedData, wxIv) {
	var deferred = Q.defer();
	//尝试解密用户数据
	try {
		//暂存sessionKey备份
		var _sessionKey = sessionKey;
		//对sessionKey进行base64解码
		sessionKey = new Buffer(sessionKey, 'base64');
		//对加密数据进行base64解码
		wxEncryptedData = new Buffer(wxEncryptedData, 'base64');
		//对iv向量进行base64解码
		wxIv = new Buffer(wxIv, 'base64');
		//使用AES-128-ABC算法利用iv向量解密sessionKey
		var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, wxIv)
		//设置自动padding为true，删除填充补位
		decipher.setAutoPadding(true)
		//更新哈希内容为加密数据，指定二进制和编码utf-8
		var decoded = decipher.update(wxEncryptedData, 'binary', 'utf8')
		//追加数据
		decoded += decipher.final('utf8');
		//将json字符串转换为对象
		decoded = JSON.parse(decoded);
		//判断appid是否匹配
		if (decoded.watermark.appid !== appid) {
			//不匹配解密失败
			deferred.reject();
		}
		//判断数据中是否存在openId
		if(decoded.openId) {
			//加入sessionKey
			decoded.sessionKey = _sessionKey;
			//加入openId
			decoded.openId = openId;
			//加入sessionKey生存时间
			decoded.expire = expire;
			//返回解密后的数据
			deferred.resolve(decoded);
		}
		else {
			//不存在则解密失败
			deferred.reject();
		}
	} catch(e) {
		//解密用户数据失败
		console.log(e);
		deferred.reject(e);
	}
	return deferred.promise;
}

//生成3rdSession函数
var create3rdSession = function(userdata) {
	var deferred = Q.defer();
	//尝试执行在linux上才能运行的生存168位随机字符串的命令
	util.execShell('head -n 80 /dev/urandom | tr -dc A-Za-z0-9 | head -c 168').then(function(_3rdSession) {
		//填入3rdSession
		userdata._3rdSession = _3rdSession;
		//返回附加了3rdSession的用户数据
		deferred.resolve(userdata);
	}, function() {
		//执行失败可能非Linux系统，使用代码生成
		//声明存储3rdSession的空字符串
		var _3rdSession = '';
		//生成随机字符串的素材
		var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
		//循环168次生成168位
		for(var i = 0;i < 168;i++) {
			//利用随机发生器和字符串数组特性获取素材中任意字符追加到3rdSession变量
			_3rdSession += str[parseInt(Math.random() * 61)];
			//如果生成已达到达到168位
			if(_3rdSession.length == 168) {
				//填入3rdSession
				userdata._3rdSession = _3rdSession;
				//返回附加了3rdSession的用户数据
				deferred.resolve(userdata);
			}
		}
	});
	return deferred.promise;
}

//存储用户数据函数
var saveUserData = function(result, storeId, tableNum) {
	var deferred = Q.defer();
	//将sessionKey和openId转换成json字符串存入变量
	var _3rdSessionData = JSON.stringify({
		sessionKey: result.sessionKey,
		openId: result.openId
	});
	//往redis添加一个key为3rdSession，value为上面的json字符串
	redis.set(result._3rdSession, _3rdSessionData).then(function() {
		console.log('登录态有效期：' + result.expire);
		//设置该值的生命周期为sessionKey的生命周期
		redis.expire(result._3rdSession, 86400);
		//存放公共数据库操作实例变量
		var commonDB = {};
		//连接到公共数据库common
		db.connectDB('common').then(function(_commonDB) {
			commonDB = _commonDB
			//查询用户列表
			return commonDB.select('users', {userId: result.openId});
		}, function() {
			//连接公用common数据库失败
			deferred.reject('-0044');
		}).then(function(data) {
			//存放需要插入的数据
			var insertData = {
				userId: result.openId,
				userName: result.nickName,
				userGender: result.gender,
				userPhoto: result.avatarUrl,
				userLanguage: result.language,
				userCountry: result.country,
				userProvince: result.province,
				userCity: result.city,
				userCurrentStore: []
			}
			//判断是否未找到对应openid的用户
			if(data.length == 0) {
				insertData.userRealName = '';
				insertData.userPhoneNumber = '';
				if(storeId && tableNum) {
					insertData.userCurrentStore.push({
						storeId: storeId,
						tableNum: tableNum
					});
				}
				//进行用户数据插入操作
				commonDB.insert('users', insertData).then(function(count) {
					if(count && count == 1) {
						//存储成功并返回3rdSession
						deferred.resolve(result);
					}
					else {
						//插入用户数据失败
						deferred.reject('-0010');
					}
				}, function() {
					//插入用户数据失败
					deferred.reject('-0010');
				});
			}
			else {
				//获得一个结果数据
				let userData = data[0];
				let updateCurrentStore = false;
				insertData.userRealName = userData.userRealName || '';
				insertData.userPhoneNumber = userData.userPhoneNumber || '';
				userData.userRealName = insertData.userRealName;
				userData.userPhoneNumber = insertData.userPhoneNumber;
				if(storeId && tableNum) {
					if(userData.userCurrentStore.length == 0) {
						insertData.userCurrentStore.push({
							storeId: storeId,
							tableNum: tableNum
						});
					}
					insertData.userCurrentStore = userData.userCurrentStore;
					for(let oldCurrentStoreIndex in userData.userCurrentStore) {
						if(userData.userCurrentStore[oldCurrentStoreIndex].storeId != storeId) {
							insertData.userCurrentStore.push({
								storeId: storeId,
								tableNum: tableNum
							});
							updateCurrentStore = true;
							break;
						}
					}
				}
				//判断数据是否都一样，如果不一样则需要将新的用户信息更新进去
				util.objEqual(insertData, userData).then(function() {
					console.log('用户信息一致');
					if(updateCurrentStore) {
						commonDB.update('users', {userId: result.openId}, insertData).then(function(count) {
							//修改完成，返回3rdSession
							deferred.resolve(result);
						}, function() {
							//mongodb更新用户信息失败
							deferred.reject('-0047');
						});
					}
					else {
						//用户已存在且信息与当前信息完全一致无需重复插入用户数据
						deferred.resolve(result);
					}
				}, function() {
					console.log('用户信息不一致');
					//数据库用户信息和微信服务器的用户信息不一致更新为最新的用户数据
					commonDB.update('users', {userId: result.openId}, insertData).then(function(count) {
						console.log('已修改' + count + '条数据');
						//修改完成，返回3rdSession
						deferred.resolve(result);
					}, function() {
						//mongodb更新用户信息失败
						deferred.reject('-0047');
					});
				});
			}
		}, function() {
			//mongodb查找用户列表失败
			deferred.reject('-0046');
		});
	}, function() {
		//设置3rdSession失败
		deferred.reject('-0045');
	});
	return deferred.promise;
}

var getStoreData = function(result) {
	var deferred = Q.defer();
	db.select('storeInfo', {}).then(function(storeInfo) {
		var storeData = {};
		var storeInfoKey = '';
		console.log(storeInfo);
		if(storeInfo.length == 0) {
			deferred.resolve(result);
		}
		else {
			for(var infoIndex in storeInfo) {
				for(var storeInfoKey in storeInfo[infoIndex]) {
					if(storeInfoKey != '_id') {
						storeData[storeInfoKey] = storeInfo[infoIndex][storeInfoKey];
						if(infoIndex == storeInfo.length - 1) {
							result.storeData = storeData;
							deferred.resolve(result);
						}
					}
				}
			}
		}
	}, function() {
		deferred.reject();
	});
	return deferred.promise;	
}

var getUnreadMsg = function(userData) {
	var deferred = Q.defer();
	if(userData.identity != 'service') {
		userData.unreadMsgs = 1;
		deferred.resolve(userData);
	}
	else {
		db.select('chatListLogs', {
			serviceReceive: false
		}).then(function(data) {
			db.updateAll('chatListLogs', {
				serviceReceive: false
			}, {
				serviceReceive: true
			}).then(function() {
				userData.unreadMsgs = data;
				deferred.resolve(userData);
			}, function() {
				deferred.reject();
			});
		}, function() {
			deferred.reject();
		});
	}
	return deferred.promise;
}

module.exports = {
	index: index
};